<?php
/**
(c) 2007 Sergey Shuchkin, shuchkin@mail.ru 

Example:
== php
V::init(array(
	"user_name" => "Your name::req",
	"user_pass" => "Your pasword::req isPass passConf=user_pass_conf",
	"user_pass_conf" => "Password confirmation::req",
	"user_email" => "Your Email::req isEmail",
	"user_code" => "Code::isInt min=1000 max=9999",
	"user_bd" => "Birthday::isDate",
	"cc_type" => "Credit card::isCC ccNum=cc_num ccM=cc_exp_month ccY=cc_exp_year",
	"cc_num" => "Credit card number::null", // title only
	"cc_exp_month" => "Expiration month::null",
	"cc_exp_year" => "Expiration year::null",
	"five_chars" => "req minlen=5 maxlen=5", // vtags only
));
if (isset($_POST['save'])) {
	if (V::success()) {
		$msg = "Data saved!";
	} else {
		$err = V::getError();
	}
}
== html
<form>
<input type="text" name="user_name" />
<input type="text" name="user_pass" />
...
<?php echo V::jsValidation(); ?>
</form>

== html (alternative method)
<form name="frmLogin>
<input type="text" name="user_name" />
<input type="text" name="user_pass" />
...
</form>
...
<?php echo V::jsValidation('frmLogin'); ?>

*/
class V extends Validator { // Short form, please remove it if conflicted
	// Your code insert here
}
class Validator {
	var $version = '1.1.3';
	var $error = false;
	var $error_arr = array();
	var $language = "en";
	var $lang = array(); // must be loaded
	var $fileExt = array(
		"images" => "jpg,jpeg,gif,png",
		"docs" => "doc,pdf,rtf,htm,html,zip,rar,7z,gz,tar",
		"video" => "avi,mpg,mpeg,flv,mov"
	);
	var $fields = array();
	var $checked = false;
	var $_about = '';
	/**
	 * Returns instance of Validator
	 * @return object link instance of Validator
	 *
	 */
	function &getInstance() {
		static $instance;
		if (!isset($instance)) {
			$c = __CLASS__;
			$instance = new $c;
			$instance->setLang();
		}
		return $instance;
	}
	function setLang($lang = "en") {
		$_this = &Validator::getInstance();
		if (defined("VALIDATOR_LANG")) $_this->language = VALIDATOR_LANG; else $_this->language = $lang;
		$filename = dirname(__FILE__).'/langs/'.$_this->language.'.xml';
		$axml = @file($filename);
		if (!$axml) die(__CLASS__.'::'.__FUNCTION__.' language file not found '.$filename);
		$xml = implode('',$axml);
		if (preg_match('/<about>(.*)<\/about>/',$xml,$r)) $_this->_about = str_replace('%v',$_this->version,$r[1]);
		if (preg_match_all('/<e_([^>]+)>(.*)<\/e_\\1>/', $xml, $r)) {
			foreach ($r[1] as $k => $v) {
				$_this->lang['e_'.$r[1][$k]] = str_replace('\n',"\n",$r[2][$k]);
			}
		}
	}
	function init($fields = array()) {
		if (!empty($fields)) {
			$_this = &Validator::getInstance();
			$_this->fields = $fields;
			$_this->checked = false;
			if (!empty($_POST)) $_this->check();
		}
	}
	function error() {
		$_this = &Validator::getInstance();
		if ($_this->checked) return $_this->error;
		else return $_this->check();
	}
	function success() {
		return !Validator::error();
	}
	function addError($str, $error_id = false, $replaces = false) {
		$_this = &Validator::getInstance();
		$_this->error = true;
		if ($error_id) {
			$str = str_replace("%s",$str,$_this->lang[$error_id]);
			if ($replaces) {
				foreach($replaces as $s => $r) $str = str_replace($s,$r,$str);
			}
		}
		$_this->error_arr[] = $str;
	}
	function getError($html = true) {
		$_this = &Validator::getInstance();
		if (!$_this->error) return "";
		if ($html) {
			$err = str_replace('\n','<br />',$_this->lang['e_msg']);
			$list = count($_this->error_arr) > 1 ? "ol" : "ul";
			$err .= "\n<$list>\n";
			foreach ($_this->error_arr as $s)
				$err .= "  <li>".str_replace('\n','<br />',$s)."</li>\n";
			$err .= "</$list>\n";
		} else {
			$err = $_this->lang['e_msg'];
			foreach ($_this->error_arr as $s)
				$err .= "\n* ".$s;
		}
		return $err;
	}
	function showError() {
		echo Validator::getError(true);
	}
	/*
	 * Main checking method
	 * $f = array(
	 *   "user_name" => "req minlen=3::Your name",
	 *   "user_email" => "req isEmail::Your email"
	 */
	function check($fields = array()) {
		$_this = &Validator::getInstance();
		if (empty($fields)) {
			$fields = $_this->fields;
		}
		$_this->error = false;
		$_this->error_arr = array();
		$req_err = false;
		foreach ($fields as $name => $vtags) {
			$value = isset($_REQUEST[$name]) ? $_REQUEST[$name] : NULL;
			$a = explode("::",$vtags);
			if (count($a) == 2) {
				$title = $a[0];
				$tags = $a[1];
			} else {
				$title = ucwords(str_replace("_"," ",$name));
				$tags = $a[0];
			}
			if (preg_match("/req|required/i",$tags)) {
				if (preg_match("/(def|default)=([^\s]+)/i",$tags,$matches)) { // <SELECT>
					if ($value == $mathes[2]) $value = NULL;
				}
				if ($value == NULL) {
					$_this->addError($title,'e_req');
					$req_err = true;
				}
			}
			if ($value != "") { // Extended types
				// Min length
				if (preg_match("/minlen\=(\d+)/i",$tags,$matches) && strlen($value)<$matches[1])
					$_this->addError($title, "e_len", array("%d"=>$matches[1]));
				// Max length / size
				if (preg_match("/maxlen\=(\d+)/i",$tags,$matches) && strlen($value)>$matches[1])
					$_this->addError($title, "e_siz", array("%d"=>$matches[1]));
				// Integer
				if (preg_match("/isInt[^P]|isInteger|is_int[^_]|is_integer/i",$tags)) {
					$min_value = $max_value = NULL;
					if (preg_match("/min\=(\-?\d+)/i",$tags,$matches)) $min_value = $matches[1];
					if (preg_match("/max\=(\-?\d+)/i",$tags,$matches)) $max_value = $matches[1];
					$s = '.';
					//alert(min_value+" "+max_value);
					if ($min_value !== NULL) $s = str_replace("%s",$min_value,$_this->lang['e_int_min']);
					if ($max_value !== NULL) $s = str_replace("%s",$max_value,$_this->lang['e_int_max']);
					if ($min_value !== NULL && $max_value !== NULL)
						$s = str_replace(array("%min","%max"),array($min_value,$max_value),$_this->lang['e_int_rng']);
					if (!$_this->isInt($value, $min_value, $max_value)) $_this->addError(str_replace("%s",$title,$_this->lang['e_int']).$s);
				}
				// Float
				if (preg_match("/isFloat|is_float/i",$tags)) {
					if (!$_this->isFloat($value)) $_this->addError($title,"e_flt");
				}
				// Email
				if (preg_match("/isEmail|is_email/i",$tags)) {
					if (!$_this->isEmail($value)) $_this->addError($title,"e_val");
				}
				// URL
				if (preg_match("/isURL|is_url/i",$tags)) {
					if (!$_this->isURL($value)) $_this->addError($title,"e_url");
				}
				// US Phone
				if (preg_match("/isUSPhone|is_us_phone/i",$tags)) {
					if (!$_this->isUSPhone($value)) $_this->addError($title,"e_uph");
				}
				// International phone
				if (preg_match("/isIntPhone|is_int_phone/i",$tags)) {
					if (!$_this->isIntPhone($value)) $_this->addError($title,"e_iph");
				}
				// Zip
				if (preg_match("/isUSZip|isZip|is_us_zip|is_zip/i",$tags)) {
					if (!$_this->isUSZip($value)) $_this->addError($title,"e_uzp");
				}
				// Date
				if (preg_match("/isDate|is_date/i",$tags)) {
					$format = $_this->lang['e_df'];
					if (preg_match("/(isDate|is_date)=([^\s]+)/i",$tags,$matches)) $format = $matches[2];
					if (preg_match("/format=([^\s]+)/i",$tags,$matches)) $format = $matches[1];
					$f_str = str_replace(array("%m","%d","%y","%Y"),array("mm","dd","yy","YYYY"),$format);
					if (!$_this->isDate($value,$format)) $_this->addError($title,"e_dat",array("%f"=>$f_str));
				}
				// Password
				if (preg_match("/isPass|isPassword|is_pass|is_password/i",$tags)) {
					$pass_conf_name = preg_match("/(passConf|pass_conf)=([^\s]+)/i",$tags,$r) ? $r[2] : $name;
					$pass_conf = $_this->getFieldInfo($pass_conf_name);
					$pass_len = preg_match("/(passLen|pass_len)=([^\s]+)/i",$tags,$r) ? $r[2] : 5;
					$pass_chars = preg_match("/(passChars|pass_chars)=([^\s]+)/i",$tags,$r) ? $r[2] : "0-9a-zA-Z\-_";
					if ($value == '' || strlen($value) < $pass_len) {
						$_this->addError($title,"e_len",array("%d" => $pass_len));
					} else if ($value != $pass_conf['value']) {
						$_this->addError($title,"e_pwd",array("%pass" => $title,"%conf"=>$pass_conf['title']));
					} else if (!preg_match("/[".$pass_chars."]+/",$value)) {
						$_this->addError($title,"e_pwc",array("%chars" => $pass_chars));
					}
				}
				// REGEX
				if (preg_match("/regex=([^\s]+)/i",$tags,$r)) {
					if (!preg_match($r[1],$value))
						$_this->addError($title,"e_val");
				}
				// File extensions
				if (preg_match("/(isFile|is_file|ext|extension)=([^\s]+)/i",$tags,$r)) {
					$ext = array_key_exists($r[2],$_this->fileExt) ? $_this->fileExt[$r[2]] : $r[2];
					if (is_null($value) && isset($_FILES[$name])) $value = $_FILES[$name]['name'];
					if (!preg_match("/(".str_replace(",","|",$ext).")$/i",$value))
						$_this->addError($title,"e_ext", array("%f"=>$ext));
				}
				// Credit card
				if (preg_match('/(isCreditCard|isCC)\s(ccNum|ccN)=([^\s]+)\s(ccExpMonth|ccM)=([^\s]+)\s(ccExpYear|ccY)=([^\s]+)/i',$tags,$r)) {
					$ni = $_this->getFieldInfo($r[3]); // number info
					if (strlen($ni['value']) == 0) {
						$_this->addError($ni['title'],"e_req");
					} else {
						$ti = $_this->getFieldInfo($name); //type info
						$mi = $_this->getFieldInfo($r[5]); // exp month info
						$yi = $_this->getFieldInfo($r[7]); // exp year info
						$_this->checkCreditCard($ti['value'], $ni['value'], $mi['value'], $yi['value'], $ti['title'], $ni['title'], $mi['title'], $yi['title']);
					}
				}
				// Plugins
				
			}		
		}
		$_this->checked = true;
		return $_this->error();
	}
	/** Returns array info field or null
	 *  ~
	 */
	
	function getFieldInfo($name) {
		$_this =& Validator::getInstance();
		$value = isset($_REQUEST[$name]) ? $_REQUEST[$name] : NULL;
		if (array_key_exists($name, $_this->fields)) {
			$a = explode("::",$_this->fields[$name]);
			if (count($a) == 2) {
				$title = $a[0];
				$tags = $a[1];
			} else {
				$title = ucwords(str_replace("_"," ",$name));
				$tags = $a[0];
			}
			return array(
				'name' => $name,
				'title' => $title,
				'tags' => $tags,
				'value' => $value
			);
		} else {
			return array(
				'name' => $name,
				'title' => ucwords(str_replace("_"," ",$name)),
				'tags' => '',
				'value' => $value
			);
		}
	}
	/**
	 * Returns specific code for validator.js
	 */
	function jsValidation($form_name = '') { // returns special validation field
		$_this =& Validator::getInstance();
		$h = '';
		foreach ($_this->fields as $k => $v) {
			$h .= "$k::$v;;";
		}
		$h = addslashes($h);
		if (empty($form_name)) return '<input type="hidden" name="_validator_" value="'.$h.'" />';
		$s = '
<script type="text/javascript">
<!--
if (typeof(document.forms["'.$form_name.'"]) != "undefined") {
	var frm = document.forms["'.$form_name.'"];
	var el = document.createElement("INPUT");
	el.type= "hidden";
	el.name= "_validator_"
	el.value = "'.$h.'";
	frm.appendChild(el);
}
-->
</script>
';
		return $s;
	}
	/**
	 * Returns true, if $number is integer number
	 *
	 * @param mixed $number tested numeric value
	 * @return true if valid, false - invalid
	 */
	function isInt($number, $minValue = NULL, $maxValue = NULL) {
		$r = preg_match('/^\-?\d+$/',$number);
		if ($r && $minValue !== NULL && $number < $minValue) return false;
		if ($r && $maxValue !== NULL && $number > $maxValue) return false;
		return $r;
	}
	
	/**
	 * Returns true if number corresponds to givenned range
	 * 
	 * Valid ranges:
	 *   '6,8,16'
	 *   '13,15-20,40'
	 *   '1,5,-3..-12.5,-16--32.12' - [..] separator recommended for negative values
	 *   '6,6' - strong 6
	 *
	 * @param integer $value checked number
	 * @param string $range see valid ranges
	 * @return boolean true if number corresponds to givenned range, else - false
	 */
	function inRange($value, $range) {
		if (strlen($range) == 0) return false;
		// comma values
		$cParts = explode(',',$range);
		if (in_array($value,$cParts)) return true;

		//range values
		if (preg_match_all('/(-?\d+)(-|\.\.)(-?\d+)/',$range,$ranges)) {
			foreach ($ranges[0] as $key => $range) {
				$x = (int) $ranges[1][$key];
				$y = (int) $ranges[3][$key];
				if ($x < $y && ($value >= $x && $value <= $y)) return true;
				if ($y < $x && ($value >= $y && $value <= $x)) return true;
			} 
		}
		return false;
	}
	/**
	 * Returns true, if $number is float number
	 *
	 * @param mixed $number tested numeric value
	 * @return true if valid, false - invalid
	 */
	function isFloat($number) {
		return is_numeric($number);
		//return preg_match('/^([+\-]?\d+|\d+)\.?\d$/',$number);
	}
	
	/**
	 * Returns true, if given string is valid domain name
	 *
	 * Valid domains:
	 *	 127.0.0.1
	 *	 google.com
	 *	 http://www.google.com/
	 *
	 * @param string $domain value to test
	 * @return boolean true if valid, false - invalid
	 **/
	function isDomain($domain) {
		if (!is_string($domain)) return false;
		
		for ($i = 0; $i < strlen($domain); $i++)
			if (ord($domain{$i}) > 127) return false;
		
		$ipDigit = '(0?0?\d|[01]?\d\d|2[0-4]\d|25[0-5])';
		$ipRE = '/^'.$ipDigit.'\.'.$ipDigit.'\.'.$ipDigit.'\.'.$ipDigit.'$/';
		//echo $ipRE;
		if (preg_match($ipRE,$domain)) return true;
		
		$domains = explode(".",$domain);

		if (count($domains) < 2) return false;
	
		foreach ($domains as $d)
			if (!preg_match('/^[a-zA-Z0-9\-]+$/',$d)) return false;

		if (strlen($domains[count($domains)-2]) < 2) return false;
	
		if (!preg_match('/^[a-zA-Z]{2,}$/',$domains[count($domains)-1])) return false;
	
		return true;

	}
	/**
	 * Returns true, if given string is valid domain name
	 *
	 * Valid urls:
	 *	 127.0.0.1
	 *	 http://127.0.0.1/index.html?query
	 *	 google.com
	 *	 http://www.google.com/search?q=IsArt
	 *
	 * @param string $url value to test
	 * @return boolean true, if given string is valid domain name, else - false
	 */
	function isURL($url) {
		if(!is_string($url)) return false;
	
		$protocolSeparatorPos = strpos($url,"://");
		$domainSeparatorPos = strpos($url,'/',$protocolSeparatorPos + 3);
	
		//if($protocolSeparatorPos == 0) return false;
		$domain = substr($url,($protocolSeparatorPos > 0 ? $protocolSeparatorPos + 3 : 0),
			($domainSeparatorPos > 0 ? $domainSeparatorPos-$protocolSeparatorPos-3 : strlen($url)));
	
		return Validator::is_domain($domain);
	}	
	/**
	 * Returns true, if given string is valid email address
	 *
	 * Valid email: login@example.com
	 * @param string $url value to test
	 * @return boolean true if given string is valid email address, else - false
	 */	
	function isEmail($email) {
		// fast method
		// return preg_match("/^[-0-9A-Z_\.]{1,50}@([-0-9A-Z_\.]+\.){1,50}([0-9A-Z]){2,4}$/i", $email);
		$atPos = strpos($email,"@");
		if ($atPos < 1 || strpos($email, '.', $atPos) === false	) return false;
	
		$login = substr($email,0, $atPos);
		$domain = substr($email, $atPos + 1);
	
		// Regexp declarations
		$loginRE = "/^[-0-9A-Z_\.]{1,50}$/i";
		//echo "$login, $loginRE";
		for ($i = 0; $i < strlen($login); $i++)
			if (ord($login{$i}) > 127) return false;

		if (!preg_match($loginRE,$login)) return false;
	
		return Validator::isDomain($domain);
	}
	/**
	 * A USA Phone Number checker
	 *
	 * Valid US number
	 *
	 *   'xxx xxx-xxxx': 312 123-1234
	 *   or 'xxx xxx-xxxx ext xxxx': 312 123-1234 ext 1234
	 * @param $phone phone number
	 * @return boolean true if $phone is valid US phone number, false - invalid
	 */
	function isUSPhone($phone) {
		return preg_match('/^((\([1-9][0-9]{2}\) *)|([1-9][0-9]{2}[\-. ]?))(\d[ -]?){6}\d *(ex[t]? *[0-9]+)?$/',$phone);
	}
	/**
	 * An international Phone Number checker
	 *
	 * Valid international phone number
	 *   '+x xxx xxx-xxxx': +1 234 567-9012
	 *   '+x xxx xxx-xxxx ext xxxx': +1 234 567-9012 ext 1234
	 *
	 * @param string $phone phone number
	 * @return boolean true if $phone is valid Int. phone number, false - invalid
	 */
	function isIntPhone($phone) {
		return preg_match('/^\+\d{1,3}[ -]\d{2,3}[ -](\d[ -]?){6}\d *(ex[t]? *[0-9]+)?$/',$phone);
	}
	/**
	 * A USA Zip Number (post code) checker
	 * 
	 * Valid US Zip number
	 *   'xxxxx': 94132
	 *   or 'xxxxx-xxxx': 94132-3213
	 *
	 * @param string $zip US zip number
	 * @return boolean true if valid, false - invalid
	 */
	function isUSZip($zip) {
		return preg_match('/(^\d{5}$)|(^\d{5}-\d{4}$)/',$zip);
	}
	/**
	 * Returns true, if checked value corresponds to specified date format
	 *
	 * @param string $date checked date
	 * @param $format see strftime() function, optional, '%m/%d/%Y' - default
	 */	 
	function isDate($date, $format = '%m/%d/%Y') {	
		$separator = " ";
		$nums = explode($separator, $format);
		if (count($nums) < 3) {
			$separator = "/";
			$nums = explode($separator, $format);
			if (count($nums) < 3) {
				$separator = ".";
				$nums = explode($separator, $format);
				if (count($nums) < 3) {
					$separator = "-";
					$nums = explode($separator, $format);
					if (count($nums) < 3){
						$separator = NULL;
					}
				}
			}
		}
		if(is_null($separator)) return false;
		$y = NULL;
		$m = NULL;
		$d = NULL;
		$a = explode($separator, $date);
		if(count($a) != 3) return false;
		$s = preg_match_all("/%./",$format,$matches);
		$b = $matches[0];
		$nlDays = array(31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
		$lDays  = array(31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
		for ($i = 0; $i < count($a); $i++) {
			if (!$a[$i]) continue;
			if (!isset($b[$i])) continue;
			switch ($b[$i]) {
				case "%d":
				case "%e":
					$d = (int) $a[$i];
					if($d < 0 || $d > 31)
						$d = -1;
					break;
				case "%m":
					$m = (int) $a[$i] - 1;
					if ($m > 11 || $m < 0)
						$m = -1;
					break;
				case "%Y":
				case "%y":
					$y = (int) $a[$i];
					if ($y < 100) $y += ($y > 29) ? 1900 : 2000;
					break;
			}
		}
		if (is_null($y) || is_null($m) || is_null($d)) return false;
		if ($m != -1) {
			if (($y % 4) == 0) {
				if (($y % 100) == 0 && ($y % 400) != 0){
					if($d > $nlDays[$m]){
						$d = -1;
					}
				}
				if ($d > $lDays[$m]) {
					$d = -1;
				}
			} else {
				if($d > $nlDays[$m]){
					$d = -1;
				}
			}
		}
		if ($y != 0 && $m != -1 && $d != -1){
			return true;
		}	
		return false;
	}
	/**
	 * Returns true if Credit Card information is correct
	 *
	 * @param string $cardType credit card type (V - Visa,M - Mastercard,A - America Express, D - Diners Club)
	 * @param string $cardNumber credit card number (With - or . or nothing)
	 * @param integer $expireMonth expire month (format is 06 or 6)
	 * @param integer $expireYear expire year (format is 01)
	 * @return boolean true if card is valid, false if card is invalid,
	 * @return global $CardValidationError - Card validation error
	 */
	function checkCreditCard($cardType, $cardNumber, $expireMonth, $expireYear, $typeTitle = '', $numTitle = '', $mTitle = '', $yTitle = '') {
		global $CardValidationError;
		$CardValidationError = '';

		$isValid = false;
		$_this =& Validator::getInstance();
		if (Validator::_getCardInfo($cardType)) {	
			if (Validator::_checkCardLenght($cardNumber, $cardType)) {
				if (Validator::_checkCardExpireDate($expireMonth,$expireYear)) {
					if (Validator::_checkCardNumber($cardNumber, $cardType) && Validator::_checkCardNumberMod10($cardNumber)) {
						$isValid = true;
					} else {
						$CardValidationError = "Invalid Card Number";
						$_this->addError($numTitle, 'e_ccn');
					}
				} else {
					$CardValidationError = "Invalid Expiration Date";
					$_this->addError($mTitle.'/'.$yTitle, 'e_cce');
				}
			} else {
				$CardValidationError = "Invalid Card Number lenght";
				$_this->addError($numTitle, 'e_ccl');
			}
		} else {
			$CardValidationError = "Unsupported Credit Card type";
			$_this->addError($typeTitle,'e_cct');
		}
		return $isValid;
	}
	/**
	 * Return Default card info with fixed lenght and initial number
	 *
	 * @param string $cardType (V - Visa, M - MasterCard, A - American Express, D - Diners Club ...)
	 * @return array
	 *    'type' - type of card (V,M,A...)
	 *    'name' - name of card service, ex: Visa
	 *    'start' - first digit(s) of card number, ex: 4
	 *    'length' - length(s) of card number, ex: 13,16
	 *
	 * @return boolean false for unsupported cards
	 */
	function _getCardInfo($cardType) {
		if (strlen($cardType = strtoupper($cardType)) != 1) return false;
		$arrayCard = array(
			'V' => array('type' => 'V', 'name' => 'Visa', 'start' => '4', 'length' => '13,16'),
			'M' => array('type' => 'M', 'name' => 'MasterCard', 'start' => '51,52,53,54,55', 'length' => '16'),
			'D' => array('type' => 'D', 'name' => 'DiscoverCard', 'start' => '6011', 'length' => '16'),
			'A' => array('type' => 'A', 'name' => 'AmericanExpress', 'start' => '34,37', 'length' => '15'),
			'C' => array('type' => 'C', 'name' => 'DinersClub', 'start' => '30,36,38', 'length' => '14'),
			'J' => array('type' => 'J', 'name' => 'JCBCard', 'start' => '3088,3096,3112,3158,3337,3528', 'length' => '16'),
			'E' => array('type' => 'E', 'name' => 'enRouteCard', 'start' => '2014,2149', 'length' => '15')
		);
		if (array_key_exists($cardType,$arrayCard))
			return $arrayCard[$cardType];
		else
			return false;
	}
	/**
	 * Check length of credit card number
	 *
	 * @param string $cardNumber credit card number
	 * @param string $cardType credit card type (V - Visa, M - Mastercard, A - American Express, D - Diners)
	 * @return boolean true if card is valid, false if card is invalid
	 */
	function _checkCardLenght($cardNumber,$cardType) {
		$checkSize = false;
		if ($cardInfo = Validator::_getCardInfo($cardType)) {
			$arraySize = explode(",",$cardInfo['length']);		
			foreach ($arraySize as $size) {		
				if ($size == strlen($cardNumber)) {
					$checkSize = true;
					break;
				}
			}
		}
		return $checkSize;
	}
	/**
	 * Check Credit Card number
	 *
	 * @param string $cardNumber credit card number
	 * @param string $cardType (V - Visa, M - Mastercard, A - America Express, D - DiscoverCard, C-Diners Club, J - JCBCard, E-enRouteCarde)
	 * @return boolean true if card is valid, false if card is invalid 
	 */
	function _checkCardNumber($cardNumber,$cardType) {
		$checkNumber = false;
	
		if ($cardInfo = Validator::_getCardInfo($cardType)) {
			$arrayStart = explode (",",$cardInfo['start']);
			foreach ($arrayStart as $start) {
				if (substr($cardNumber,0,strlen($start)) == $start) {
					$checkNumber = true;
					break;
				}
			}
		}		
		return $checkNumber;
	}
	/** 
	* Specific Mod10 test of Credit Card number
	*
	* @cardNumber string credit card number 
	* @return boolean true if card is valid, false if card is invalid
	**/
	function _checkCardNumberMod10($cardNumber) {
		$checkSum = 0;
		$cc = array(16);
		for ($i = 0; $i < strlen($cardNumber); $i++) {
			$cc[$i] = floor (substr($cardNumber,$i,1));
		}	
			
		for ($i = (strlen($cardNumber) % 2); $i < strlen($cardNumber); $i+=2) {
			$a = $cc[$i] * 2;
			if ($a >= 10) {
				$a = "$a";
				$b = substr($a,0,1);
				$c = substr($a,1,1);
				$cc[$i] = floor($b) + floor($c);	
			} else {
				$cc[$i] = $a;
			}
		}
		
		for ($i = 0; $i < strlen($cardNumber); $i++) {
			$checkSum += floor ($cc[$i]);
		}		
		$validCc = (($checkSum % 10) == 0);	
		return $validCc;		
	}
	/**
	 * Check expiration date of Credit Card
	 *
	 * @param string $expireMonth expire month (format is 06 or 6)
	 * @param string $expireYear expire year (format is 01)
	 * @return boolean true if card is valid, false if card is invalid
	 */
	 function _checkCardExpireDate($expireMonth = "00",$expireYear = "00") {
		if  ((
			   ((int) $expireYear > (int) Date("y"))
			|| 
			   ((int) $expireMonth > (int) Date("m") && (int) $expireYear == (int) Date("y")) 
			   )
			&&
			   ($expireMonth != "00" && $expireYear != "00" && $expireMonth != "" && $expireYear != "")
			)
			return true;
		else
			return false;
	}

	/*-------------------------------------- ADDITIONAL METHODS ------------------------------*/
	function strip(&$text) {
		$text = trim(eregi_replace(" +", " ",$text));
		$search = array("\"", "'", "\\", '\"', "\'", "<", ">", "&nbsp;");
		$replace = array("&quot;", "&#39;", "&#92;", "&quot;", "&#39;", "&lt;", "&gt;", " ");
		$text = str_replace($search, $replace, $text);
		return $text;
	}
	function checkXSS($value) {
		if ((eregi("<[^>]*script*\"?[^>]*>", $value)) || (eregi("<[^>]*object*\"?[^>]*>", $value)) ||
			(eregi("<[^>]*iframe*\"?[^>]*>", $value)) || (eregi("<[^>]*applet*\"?[^>]*>", $value)) ||
			(eregi("<[^>]*meta*\"?[^>]*>", $value)) || (eregi("<[^>]*style*\"?[^>]*>", $value)) ||
			(eregi("<[^>]*form*\"?[^>]*>", $value)) || (eregi("\([^>]*\"?[^)]*\)", $value)) ||
			(eregi("\"", $value)))
			return true;
		return false;
	}
	function about() {
		$_this = &Validator::getInstance();
		echo '<h2>'.$_this->_about.'</h2>';
	}
} // end of Validator
?>